/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package sim.execution;

import java.io.FileInputStream;
import java.io.IOException;
import java.util.Collections;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import sim.helpers.Variables;
import java.util.Scanner;
import sim.helpers.Helper;
import sim.helpers.statistics.StatisticsExporter;
import sim.helpers.statistics.StatisticsHolder;
import sim.helpers.comparers.ValueHolderComparer;

/**
 *
 * @author artem
 */
public class SingleExecution {

    private String properties;
    
    public SingleExecution(String properties) {
        this.properties = properties;
    }

    /**
     * @param args the command line arguments
     */
    public void execute(String[] args) {
        setNumberOfAvailableCores();
        Executor[] executors = new Executor[Variables.numberOfCores];
        Helper helper = new Helper();
        setupSimDefaults(helper);
        setupStatisticsHolders();
        for (int i = 0; i < Variables.numberOfCores; i++) {
            executors[i] = new Executor(i, helper.clone());
        }
        waitAndExportStatistics(executors, helper);
    }

    private void setNumberOfAvailableCores() {
        Runtime runtime = Runtime.getRuntime();
        Variables.numberOfCores = runtime.availableProcessors();
        System.out.println("Found " + Variables.numberOfCores + " cores.");
        System.out.print("Enter number of cores to engage, or <Enter> for all: ");
        Scanner in = new Scanner(System.in);
        String tmpNoOfCores = in.nextLine().trim();
        if (!tmpNoOfCores.isEmpty()) {
            if (Integer.parseInt(tmpNoOfCores) > Variables.numberOfCores) {
                System.out.print("You entered more cores than available, switching to " + Variables.numberOfCores);
            } else {
                Variables.numberOfCores = Integer.parseInt(tmpNoOfCores);
            }
        }
        return;
    }

    private void setupSimDefaults(Helper helper) {
        System.out.print("Read config [Y/n]? ");
        Scanner in = new Scanner(System.in);
        String ans = in.nextLine().trim();
        if (ans.equals("") || ans.equalsIgnoreCase("y")) {
            readConfig(helper);
        } else {
            newSim(helper, in);
        }
        
    }

    private void readConfig(Helper helper) {
        Properties config = new Properties();
        try {
            FileInputStream confFile = new java.io.FileInputStream(properties);
            config.load(confFile);
        } catch (IOException ex) {
            Logger.getLogger(SingleExecution.class.getName()).log(Level.SEVERE, null, ex);
            System.out.println("[ERR] Could not open configuration file \"default.properties\"");
            return;
        }
        helper.N = Integer.parseInt(config.getProperty("NODES").trim());
        helper.H = Integer.parseInt(config.getProperty("HEADS").trim());
        helper.L = Integer.parseInt(config.getProperty("LENGTH").trim());
        helper.QOS = Integer.parseInt(config.getProperty("QOS").trim());
        helper.SD = Integer.parseInt(config.getProperty("SD").trim());
        helper.R = Integer.parseInt(config.getProperty("RADIUS").trim());
        Variables.changingConstant = config.getProperty("CHANGING_CONSTANT").trim();
        Variables.minValue = Integer.parseInt(config.getProperty("MINIMUM").trim());
        Variables.maxValue = Integer.parseInt(config.getProperty("MAXIMUM").trim());
        Variables.increment = Integer.parseInt(config.getProperty("INCREMENT").trim());
        Variables.repetitions = Integer.parseInt(config.getProperty("REPETITIONS").trim());
        System.out.println("Configuring Done.\n");
    }

    private void newSim(Helper helper, Scanner in) {
        System.out.print("Enter default N: ");
        helper.N = Integer.parseInt(in.nextLine().trim());

        System.out.print("Enter default H: ");
        helper.H = Integer.parseInt(in.nextLine().trim());

        System.out.print("Enter default L: ");
        helper.L = Integer.parseInt(in.nextLine().trim());

        System.out.print("Enter default QoS: ");
        helper.QOS = Integer.parseInt(in.nextLine().trim());

        System.out.print("Enter default SD: ");
        helper.SD = Integer.parseInt(in.nextLine().trim());

        System.out.print("Enter default R: ");
        helper.R = Integer.parseInt(in.nextLine().trim());

        System.out.print("Enter changing constant (N, H, L, QOS, SD): ");
        Variables.changingConstant = in.nextLine();

        System.out.print("Enter minimum value: ");
        Variables.minValue = Integer.parseInt(in.nextLine().trim());

        System.out.print("Enter maximum value: ");
        Variables.maxValue = Integer.parseInt(in.nextLine().trim());

        System.out.print("Enter increment: ");
        Variables.increment = Integer.parseInt(in.nextLine().trim());

        System.out.print("Enter repetitions: ");
        Variables.repetitions = Integer.parseInt(in.nextLine().trim());

        System.out.println("Configuring Done.\n");
    }

    private void setupStatisticsHolders() {
        Variables.NLiSH = new StatisticsHolder();
        Variables.CcSH = new StatisticsHolder();
        Variables.AccSH = new StatisticsHolder();
    }

    private void waitAndExportStatistics(Executor[] executors, Helper helper) {
        for (int i = 0; i < executors.length; i++) {
            try {
                executors[i].runner.join();
            } catch (InterruptedException ex) {
                Logger.getLogger(SingleExecution.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        Collections.sort(Variables.NLiSH.getValueList(), new ValueHolderComparer());
        Collections.sort(Variables.CcSH.getValueList(), new ValueHolderComparer());
        Collections.sort(Variables.AccSH.getValueList(), new ValueHolderComparer());
        System.out.println("All threads have finished execution.\nExporting Statistics..");
        StatisticsExporter.Export(helper);
        System.out.println("Done.\nExiting.\n");
    }
}
